package com.ruoyi.common.utils.file;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.ruoyi.common.config.AiBaseInfoConfig;
import com.ruoyi.common.config.LlmInfoConfig;
import com.ruoyi.common.utils.MinerUUtils;
import com.ruoyi.common.utils.min_io.MinIOUtil;
import com.ruoyi.common.utils.python.PythonCommandUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.pdfbox.Loader;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static java.io.File.separator;

@Slf4j
public class FileParseUtils {

    /**
     * textin处理文件
     *
     * @param file
     * @return
     */
    public static String textinSwitchToPicture(MultipartFile file) {
        String fileStringContent = "";
        String text = "";
        try {
            fileStringContent = TextinOcr.getPdfToMdResult(file);
            text = PDFUtils.convertTextToMarkdownSaveImage(fileStringContent);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("textin解析图片时出错：" + e);
        }
        if (text.isEmpty()) {
            // 失败处理
            text = fileStringContent;
        }
        return text;
    }

    /**
     * vl 处理文件
     *
     * @param file
     * @return
     * @throws Exception
     */
    public static String vlSwitchToPicture(MultipartFile file) throws Exception {
        String text = "";
        // 将pdf拆分成图片
        ArrayList<String> imageUrls = pdfSwitchToPicture(file);
        log.info(" MinIo imageUrls: " + imageUrls);
        System.err.println(imageUrls);
        // 调用TongyiUtils进行解析
        try {
            text = agentVlByHttp(imageUrls);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("vl解析图片时调用TongyiHttp解析图片时出错：" + e);
        } finally {
            imageUrls.forEach(MinIOUtil::removeFile);
        }
        return text;
    }

    /**
     * 调用vl解析图片中的文字（http版）
     *
     * @param resourceUrls 图片路径
     * @return API 的响应
     */
    public static String agentVlByHttp(List<String> resourceUrls) {
        // 动态传入API地址和模型名称
        String apiUrl = AiBaseInfoConfig.getOpenAiVlUrl();
        String model = AiBaseInfoConfig.getVlModel();
        // 创建固定大小的线程池（建议根据实际情况配置线程数）
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        StringBuilder text = new StringBuilder();

        try {
            // 将每个URL包装成Callable任务
            List<Callable<String>> tasks = new ArrayList<>();
            for (String url : resourceUrls) {
                Thread.sleep(200);
                tasks.add(() -> {
                    log.info("Processing image URL: {}", url);
                    return processImageUrl(apiUrl, model, url);
                });
            }
            // 批量提交所有任务并等待全部完成（关键改进点）
            List<Future<String>> futures = executorService.invokeAll(tasks);

            // 按任务提交顺序收集结果
            for (Future<String> future : futures) {
                try {
                    text.append("^^^^^^^^").append(future.get());
                } catch (Exception e) {
                    log.error("线程处理图片处理失败: {}", e.getMessage());
                    // 根据业务需求决定是否添加默认值或继续抛出异常
                    throw new RuntimeException("处理图片失败: " + e);
                }
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new RuntimeException("处理被中断" + e);
        } finally {
            // 优雅关闭线程池
            executorService.shutdown();
            try {
                if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) {
                    List<Runnable> unfinished = executorService.shutdownNow();
                    log.warn("强制关闭了 {} 个未完成任务", unfinished.size());
                }
            } catch (InterruptedException e) {
                executorService.shutdownNow();
                Thread.currentThread().interrupt();
            }

            // 清理资源
            FileUtils.deleteFolderContentsOnly(LlmInfoConfig.getProfile() + separator + "temp");
        }

        return text.toString();
    }


    /**
     * 处理单个图片URL的方法
     */
    public static String processImageUrl(String apiUrl, String model, String resourceUrl) {
        try {
            // 创建URL对象并打开连接
            URL url = new URL(apiUrl);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();

            // 设置请求方法为POST，并设置Content-Type头部信息
            conn.setRequestMethod("POST");
            conn.setRequestProperty("Content-Type", "application/json; utf-8");
            conn.setRequestProperty("Authorization", "Bearer ");
            conn.setDoOutput(true);

            // 构建请求体的JSON对象
            JsonObject jsonObject = new JsonObject();
            jsonObject.addProperty("model", model);

            // 构造messages数组
            JsonArray messages = new JsonArray();

            // system角色消息
            JsonObject systemMessage = new JsonObject();
            systemMessage.addProperty("role", "system");
            JsonArray systemContent = new JsonArray();
            JsonObject textPart = new JsonObject();
            textPart.addProperty("type", "text");
            textPart.addProperty("text", "# 角色 \n 你是一位图片文字提取助手。 # 任务 请提取图片中的文本，如果文件中有水印请去除水印内容按原文返回，如果遇到表格请用html格式输出，其他文字则保持原格式内容，禁止输出其他解释性文字");
            systemContent.add(textPart);
            systemMessage.add("content", systemContent);
            messages.add(systemMessage);

            // user角色消息
            JsonObject userMessage = new JsonObject();
            userMessage.addProperty("role", "user");
            JsonArray userContent = new JsonArray();
            JsonObject textPartUser = new JsonObject();
            textPartUser.addProperty("type", "text");
            textPartUser.addProperty("text", "请提取图片中的文本，如果文件中有水印请去除水印内容按原文返回，如果遇到表格请用html格式输出，其他文字则保持原格式内容，禁止输出其他解释性文字");
            userContent.add(textPartUser);

            // 图片部分
            JsonObject imagePart = new JsonObject();
            imagePart.addProperty("type", "image_url");

            if ("qwen2.5-VL-32B".equals(model)) {
                JsonObject urlparams = new JsonObject();
                urlparams.addProperty("url", resourceUrl);
                imagePart.add("image_url", urlparams);
            } else {
                imagePart.addProperty("image_url", resourceUrl);
            }
            userContent.add(imagePart);
            userMessage.add("content", userContent);
            messages.add(userMessage);

            jsonObject.add("messages", messages);
            jsonObject.addProperty("temperature", 0.7);

            // 发送请求
            try (OutputStream os = conn.getOutputStream()) {
                byte[] input = jsonObject.toString().getBytes("utf-8");
                os.write(input, 0, input.length);
            }

            // 获取响应
            int responseCode = conn.getResponseCode();
            if (responseCode == HttpURLConnection.HTTP_OK) {
                try (BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()))) {
                    StringBuilder content = new StringBuilder();
                    String inputLine;
                    while ((inputLine = in.readLine()) != null) {
                        content.append(inputLine);
                    }

                    // 解析JSON响应
                    com.google.gson.JsonObject jsonResponse = JsonParser.parseString(content.toString()).getAsJsonObject();

                    log.error("Request Body: {}", jsonObject);

                    return jsonResponse.getAsJsonArray("choices").get(0).getAsJsonObject().getAsJsonObject("message").get("content").getAsString();
                }
            } else {
                StringBuilder content = new StringBuilder();
                try (BufferedReader in = new BufferedReader(new InputStreamReader(conn.getErrorStream()))) {
                    content = new StringBuilder();
                    String inputLine;
                    while ((inputLine = in.readLine()) != null) {
                        content.append(inputLine);
                    }
                }
                log.error("API返回错误 | 状态码: {} | 信息: {},图片路径，{}", responseCode, content, resourceUrl);
                // 用String拼接起来
                String msg = "API返回错误 | 状态码: " + responseCode + " | 信息: " + content + "图片路径，" + resourceUrl;
                return "";
            }
        } catch (Exception e) {
            log.error("处理图片失败: " + e.getMessage());
            return "";
        }
    }

    /**
     * 将PDF文档拆分成多张图片，并返回所有图片的路径
     *
     * @param pdfPath PDF文件的路径
     * @return
     * @throws Exception
     */
    public static List<String> pdfSwitchToPicture(String pdfPath) throws Exception {
        List<String> picUrlList = new ArrayList<>();
        File file = new File(LlmInfoConfig.getProfile() + File.separator + "temp");
        if (!file.exists()) {
            file.mkdirs();
        }
        String pictureRootName = file.getName() + "_";
        List<byte[]> imageList = handlePdf(pdfPath);
        AtomicInteger pictureNameNumber = new AtomicInteger(1);

        for (byte[] image : imageList) {
            String pictureUrl = file.getAbsolutePath() + File.separator + pictureRootName + pictureNameNumber.getAndIncrement() + ".jpg";
            try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); FileOutputStream fileOutputStream = new FileOutputStream(pictureUrl)) {
                byteArrayOutputStream.write(image);
                byteArrayOutputStream.writeTo(fileOutputStream);
                picUrlList.add(pictureUrl);
            } catch (IOException e) {
                log.error("处理PDF图片失败: " + e.getMessage());
                throw e;
            }
        }
        return picUrlList;
    }

    /**
     * 处理PDF文档
     *
     * @param pdfPath
     * @return
     * @throws Exception
     */
    public static List<byte[]> handlePdf(String pdfPath) throws Exception {
        File pdfFile = new File(pdfPath);
        // 加载PDF文档
        PDDocument pdDocument = Loader.loadPDF(pdfFile);
        // 创建PDF渲染器
        PDFRenderer pdfRenderer = new PDFRenderer(pdDocument);
        int pageNum = pdDocument.getNumberOfPages();
        List<byte[]> list = new ArrayList<>();
        for (int i = 0; i < pageNum; i++) {
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            // 将PDF的每一页渲染成一张图片，并放大1.5倍
            BufferedImage image = pdfRenderer.renderImage(i, 1.5F);
            ImageIO.write(image, "jpg", outputStream);
            list.add(outputStream.toByteArray());
            outputStream.close();
        }
        pdDocument.close();
        return list;
    }

    /**
     * 将文件路径转换为MultipartFile对象
     *
     * @param filePath 文件路径
     * @return MultipartFile对象
     * @throws IOException 如果文件读取过程中发生错误
     */
    public static MultipartFile convertFileToMultipartFile(String filePath) throws IOException {
        File file = new File(filePath);
        byte[] fileContent = Files.readAllBytes(file.toPath());
        String fileName = file.getName();
        String contentType = Files.probeContentType(file.toPath());
        return new CustomMultipartFile(fileContent, fileName, fileName, contentType);
    }

    /**
     * 将 PDF 文档拆分成多张图片，并返回所有图片的路径
     *
     * @param file
     * @return
     * @throws Exception
     */
    public static ArrayList<String> pdfSwitchToPicture(MultipartFile file) throws Exception {
        // 将 MultipartFile 转换为 File
        File pdfFile = convertMultipartFileToFile(file);

        // 调用 pdfSwitchToPicture 方法
        List<String> imagePaths = pdfSwitchToPicture(pdfFile.getAbsolutePath());

        // 删除临时文件
        pdfFile.delete();

        // 服务器url
        ArrayList<String> url = new ArrayList<>();

        // 上传本地文件到 MinIO
        imagePaths.forEach(imagePath -> {
            try {
                MultipartFile multipartFile = convertFileToMultipartFile(imagePath);
                Map<String, String> stringStringMap = MinIOUtil.putObject(multipartFile, "image_file/");
                url.add(stringStringMap.get("fileUrl"));
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        });

        for (String imagePath : imagePaths) {
            File imageFile = new File(imagePath);
            if (imageFile.exists()) {
                imageFile.delete();
            }
        }


        return url;
    }

    /**
     * 将MultipartFile转换为File
     *
     * @param multipartFile
     * @return
     * @throws IOException
     */
    public static File convertMultipartFileToFile(MultipartFile multipartFile) throws IOException {
        File convFile = new File(multipartFile.getOriginalFilename());
        convFile.createNewFile();
        try (FileOutputStream fos = new FileOutputStream(convFile)) {
            fos.write(multipartFile.getBytes());
        }
        return convFile;
    }

    /**
     * 去除文件内容中的页码
     *
     * @param text
     * @return
     */
    public static String removeAllPageMarkers(String text) {
        String pattern = "(?x)" + "(?<=\\n|\\A)" + "\\s*" + "(?:<!--)?" + "[\\p{Punct}\\\\—*·\\s]*" + "(?:" + "  (?<num>\\d+)" + "  |" + "  第\\s*(?<chnum>[\\d\\uFF10-\\uFF19]+)\\s*[页頁]" + "  |" + "  (?i:page\\s*(?<engnum>\\d+))" + ")" + "[\\p{Punct}\\\\—*·\\s]*" + "(?:-{2,3}|—{2,3})?" + "\\s*" + "(?=\\n|\\z)";

        return text.replaceAll(pattern, "");
    }

    /**
     * 解析不同类型的文件内容
     *
     * @param files minio 地址
     * @return 返回jsonArray 其中对象中的content 存储原文
     */
    public static String parseFileToContent(List<String> files) throws Exception {
        // 返回内容
        JSONArray jsonArray = new JSONArray();

        // 进行多文件遍历
        for (String file : files) {
            // 获取原始文件名并进行URL解码
            String fileName = MinIOUtil.getFileName(file);
            MultipartFile fileMultipartFile = MinIOUtil.getFileMultipartFile(file);


            log.info("当前处理的文件为：{}", fileName);
            // 获取文件扩展名
            String suffix = FileUtils.getFileExtension(fileName).toLowerCase();


            // 判断文件后缀
            if (suffix.equals("md") || suffix.equals("txt") || suffix.equals("pdf") || suffix.equals("docx") || suffix.equals("doc") || suffix.equals("pptx") || suffix.equals("ppt") || suffix.equals("xlsx") || suffix.equals("xls") || suffix.equals("eml") || suffix.equals("msg") || suffix.equals("oft") || suffix.equals("jpg") || suffix.equals("png")) {
                // 进行返回操作
                JSONObject json = new JSONObject();
                // 文件内容
                json.put("content", "");
                // 源文件路径
                json.put("path", file);
                // 文件名称 - 使用解码后的文件名
                json.put("name", fileName);
                // 文件类型
                json.put("type", suffix);
                // 解析md文件和txt文件
                if (suffix.equals("md") || suffix.equals("txt")) {
                    // 读取md或txt文件的内容
                    String fileStringContent = PDFUtils.readMarkdownFile(fileMultipartFile.getInputStream());
                    String text = PDFUtils.convertTextToMarkdownSaveImage(fileStringContent);
                    if (text.isEmpty()) {
                        text = fileStringContent;
                    }
                    // 文件文字内容
                    json.put("content", text);
                }
                // 解析pdf文件
                else if (suffix.equals("pdf")) {
                    // 文件原文
                    String text;
                    try {
                        String s = MinerUUtils.connectionMinerU(file);
                        text = MinerUUtils.taskMinerU(s);
                        //text = vlSwitchToPicture(file);
                    } catch (Exception e) {
                        try {
                            log.error("【minerU转换失败】：", e);
                            text = textinSwitchToPicture(fileMultipartFile);
                        } catch (Exception e1) {
                            text = vlSwitchToPicture(fileMultipartFile);
                            log.error("【textIn转换失败】：", e);
                        }

                    }
                    // 存入到返回对象中
                    json.put("content", text);

                }

                // 解析文档文件
                else if (suffix.equals("docx") || suffix.equals("doc")) {
                    String text = "";
                    // 使用pandoc将docx转换为md
                    // 直接返回这个pdf文本信息 不带图片信息
                    // File file1 = convertMultipartFileToFile(file);
                    String filePath = null;
                    //todo 目前采用mineru 进行成本控制
                    try {
                        if (suffix.equals("docx")) {
                            String s = MinerUUtils.connectionMinerU(file);
                            text = MinerUUtils.taskMinerU(s);
                           /* filePath = saveAsTempFile(file);
                            text = DocxUtils.localConvertDocxToMdWithImagesFromPath(filePath, fileName);*/
                        } else {
                            String s = MinerUUtils.connectionMinerU(file);
                            text = MinerUUtils.taskMinerU(s);
                            // text = DocxUtils.localConvertDocxToMdWithImages(file, fileName);
                        }
                    } catch (Exception e) {
                        log.error("【minerU转换失败】：使用textIn", e);
                        text = textinSwitchToPicture(fileMultipartFile);

                    } finally {
                        if (StrUtil.isNotBlank(filePath)) {
                            File tempFile = new File(filePath);
                            tempFile.delete();
                        }
                    }
                    //text = PDFUtils.readDocxFile(file);
                    // text = DocxUtils.localConvertDocxToMdWithImagesFromPath(file1.getPath(), fileName);
                    // 删除文件中的图片链接
                    text = text.trim().replace("\n", "").replace("\r", "").replace("\\", "");
                    // 正则过滤图片内容
                    String MoreImagesPattern = "(!\\[\\]\\([^)]+\\)(?:\\{[^}]*\\})?){4,}";
                    Pattern pattern = Pattern.compile(MoreImagesPattern);
                    Matcher matcher = pattern.matcher(text);
                    // 正则过滤图片内容
                    if (matcher.find()) {
                        // 判断过滤后的图片内容是否为空
                       /* String removeImageText = text.replaceAll(regex, "");
                        log.error("resolverFileFromInterconnection 解析Pdf文件结果: {}", text);
                        // 判断是否为空，为空的情况就调用TextIn方法
                        if (StringUtils.isBlank(removeImageText)) {*/
                        String fileStringContent = TextinOcr.getPdfToMdResult(file);
                        try {
                            text = PDFUtils.convertTextToMarkdownSaveImage(fileStringContent);
                        } catch (Exception e) {
                            throw new RuntimeException("textin解析图片时出错：" + e);
                        }
                        if (text.isEmpty()) {
                            // 失败处理
                            text = fileStringContent;
                        }

                    }

                  /*  // 是否属于结构化数据
                    if (structured_data) {
                        // 调用textin
                        String fileStringContent = TextinOcr.getPdfToMdResult(file);
                        text = PDFUtils.convertTextToMarkdownSaveImage(fileStringContent);
                        if (text.isEmpty()) {
                            // 失败处理
                            text = fileStringContent;
                        }
                    } else {

                    }*/

                    if (separator.isEmpty()) {
                        text = TextSegmenter.segmentText(text);
                    }

                    json.put("content", text);
                    json.put("name", fileName);
                }
                // 解析PPT文件
                else if (suffix.equals("pptx") || suffix.equals("ppt")) {
                    // 创建临时文件
                    File temp = new File(file);
                    // 获取文本内容
                    String content = PPTUtils.parsePPT(temp);
                    // 使用完之后进行删除
                    temp.delete();
                    json.put("content", content);
                }
                // 解析邮件文件(eml、msg、oft)
                else if (suffix.equals("eml") || suffix.equals("msg") || suffix.equals("oft")) {
                    // 保存到临时路径
                    String filePath = file;
                    // 调用python脚本解析邮件文件
                    String content = PythonCommandUtils.emailToTextFromPython(filePath);
                    // 删除临时文件
                    File tempFile = new File(filePath);
                    tempFile.delete();
                    json.put("content", content);
                }
                // 解析Excel文件
                else if (suffix.equals("xlsx") || suffix.equals("xls")) {
                    System.err.println("解析Excel文件");
                    try {
                        // 保存到临时路径
                        String filePath = saveAsTempFile(fileMultipartFile);
                        // 进行文件内容解析
                        // String content = PythonCommandUtils.excelToMarkdownFromPython(filePath, "");
                        String content = PythonCommandUtils.excelToJsonFromPython(filePath);
                        File tempFile = new File(filePath);
                        tempFile.delete();
                        json.put("content", content);
                    } catch (Exception e) {
                        log.error("解析Excel文件出错：" + e);
                        json.put("content", "解析Excel文件出错：" + e);
                    }
                }

                // System.err.println("json:" + json);

                String content = json.getString("content");

                if (isValidJson(content)) {
                    json.put("content", JSONObject.parse(content));
                } else if (isValidJsonArray(content)) {
                    json.put("content", JSONArray.parse(content));
                } else {
                    json.put("content", content);
                }

                // 添加到返回集合中
                jsonArray.add(json);
            } else {
                return "这个接口支持md|txt|pdf|docx文件";
            }
        }

        return jsonArray.toJSONString();
    }

    /**
     * 存储临时文件
     *
     * @param file
     * @return
     * @throws IOException
     */
    public static String saveAsTempFile(MultipartFile file) throws IOException {
        // 创建临时文件
        File tempFile = File.createTempFile("temp-", file.getOriginalFilename());
        file.transferTo(tempFile);

        // 返回临时文件路径
        return tempFile.getAbsolutePath();
    }

    /**
     * 判断是否是json格式
     */
    public static boolean isValidJson(String jsonString) {
        try {
            JSONObject.parseObject(jsonString);
            return true;
        } catch (Exception e) {
            // 如果抛出异常，则不是有效的JSON
            return false;
        }
    }

    /**
     * 判断是否是jsonArray格式
     */
    public static boolean isValidJsonArray(String jsonString) {
        try {
            JSONArray.parseArray(jsonString);
            return true;
        } catch (Exception e) {
            // 如果抛出异常，则不是有效的JSON
            return false;
        }
    }
}
